package com.vhall.component.plugin.common.aspect;

import cn.hutool.extra.servlet.ServletUtil;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.utils.algorithm.ISignGenerator;
import com.vhall.component.plugin.common.utils.algorithm.SignAlgorithmManager;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * API接口签名验证切面
 *
 * @author yuanzh
 * @date 2021/9/8
 */
@Slf4j
@Aspect
@Component
public class ApiSignatureValidatorAspect extends BaseDataAspect {


    @Value("${paas.apps.lite.appSecret}")
    public String appSecret;


    @Pointcut("@annotation(com.vhall.component.plugin.common.annotation.ApiSignatureAuth)|| @within(com.vhall.component.plugin.common.annotation.ApiSignatureAuth)")
    public void pointCut() {
        // Do nothing
    }

    @Around("pointCut()")
    public Object checkSign(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(servletRequestAttributes, "请求参数异常");
        HttpServletRequest request = servletRequestAttributes.getRequest();
        try {
            Map<String, String> parameterMap = ServletUtil.getParamMap(request);
            String signature = parameterMap.get("sign");


            if (validMockFlag(request)) {
                return joinPoint.proceed(args);
            }

            parameterMap.remove("sign");

            // signType -> MD5 SHA-256
            String defaultSignType = parameterMap.getOrDefault("sign_type", SignAlgorithmManager.MD5_SIGN_TYPE);
            ISignGenerator signGenerator = SignAlgorithmManager.getByName(defaultSignType);
            String signContent = SignAlgorithmManager.getSignContent(parameterMap);

            if (!signGenerator.verify(signContent, StandardCharsets.UTF_8.toString(), appSecret, signature)) {
                log.error("API接口验签失败，接口uri：{}", request.getRequestURI());
                throw new BusinessException(BizErrorCode.AUTH_LOGIN_SIGN_FAIL);
            }
            return joinPoint.proceed(args);
        } catch (Throwable e) {
            log.error("", e);
            throw e;
        }
    }
}
